package com.backend.modules.task.schedule;

import com.backend.common.utils.RedisUtils;
import com.backend.modules.notification.service.NotificationService;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.task.entity.Task;
import com.backend.modules.task.entity.TaskSubmission;
import com.backend.modules.task.repository.TaskRepository;
import com.backend.modules.task.service.EmailService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class TaskSchedule {

    private final TaskRepository taskRepository;
    private final NotificationService notificationService;
    private final EmailService emailService;
    private final RedisUtils redisUtils;

    // Redis key前缀
    private static final String REMINDER_KEY_PREFIX = "task:deadline:reminder:";
    
    /**
     * 每5分钟检查一次即将截止的任务
     * 检查未来24小时内截止的任务，并给未提交的学生发送提醒
     */
    @Scheduled(fixedRate = 300000) // 5分钟 = 300000毫秒
    @Transactional(readOnly = true)
    public void checkDeadline() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime tomorrow = now.plusDays(1);

        try {
            // 查询24小时内即将截止的任务
            List<Task> tasks = taskRepository.findByDeadlineBetween(now, tomorrow);
            
            for (Task task : tasks) {
                // 获取已提交的学生ID集合
                Set<Long> submittedStudentIds = task.getSubmissions().stream()
                    .map(submission -> submission.getStudent().getId())
                    .collect(Collectors.toSet());
                
                // 获取班级所有学生
                List<SysUser> allStudents = task.getClassInfo().getStudents();
                
                // 筛选出未提交的学生
                List<SysUser> unsubmittedStudents = allStudents.stream()
                    .filter(student -> !submittedStudentIds.contains(student.getId()))
                    .collect(Collectors.toList());
                
                // 计算剩余时间
                Duration timeLeft = Duration.between(now, task.getDeadline());
                String timeLeftStr = formatDuration(timeLeft);
                
                // 根据剩余时间决定是否发送提醒
                if (shouldSendReminder(timeLeft)) {
                    // 给每个未提交的学生发送提醒
                    for (SysUser student : unsubmittedStudents) {
                        // 检查是否已经发送过提醒
                        String reminderKey = getReminderKey(task.getId(), student.getId(), timeLeft);
                        if (!hasSentReminder(reminderKey)) {
                            emailService.sendDeadlineReminderEmail(student, task, timeLeftStr);
//                            notificationService.sendDeadlineReminder(student, task);
                            markReminderSent(reminderKey, timeLeft);
                            
                            log.info("发送任务截止提醒 - 任务：{}，学生：{}, 剩余时间：{}", 
                                task.getName(), student.getUsername(), timeLeftStr);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("检查任务截止时间时发生错误", e);
        }
    }
    
    /**
     * 判断是否需要发送提醒
     * 在以下时间范围内发送提醒：
     * - 24-20小时
     * - 12-8小时
     * - 4-2小时
     * - 1小时内
     */
    private boolean shouldSendReminder(Duration timeLeft) {
        long hours = timeLeft.toHours();
        return (hours <= 24 && hours > 20) ||  // 24-20小时
               (hours <= 12 && hours > 8) ||   // 12-8小时
               (hours <= 4 && hours > 2) ||    // 4-2小时
               hours <= 1;                     // 1小时内
    }
    
    /**
     * 格式化时间间隔
     */
    private String formatDuration(Duration duration) {
        long hours = duration.toHours();
        if (hours >= 24) {
            return duration.toDays() + "天";
        } else if (hours >= 1) {
            return hours + "小时";
        } else {
            return duration.toMinutes() + "分钟";
        }
    }

    /**
     * 生成Redis中提醒记录的键
     */
    private String getReminderKey(Long taskId, Long studentId, Duration timeLeft) {
        long hours = timeLeft.toHours();
        String timeRange;
        if (hours <= 24 && hours > 20) {
            timeRange = "24h";
        } else if (hours <= 12 && hours > 8) {
            timeRange = "12h";
        } else if (hours <= 4 && hours > 2) {
            timeRange = "4h";
        } else {
            timeRange = "1h";
        }
        return REMINDER_KEY_PREFIX + taskId + ":" + studentId + ":" + timeRange;
    }

    /**
     * 检查是否已发送过提醒
     */
    private boolean hasSentReminder(String reminderKey) {
        return redisUtils.hasKey(reminderKey);
    }

    /**
     * 标记提醒已发送，并设置过期时间
     */
    private void markReminderSent(String reminderKey, Duration timeLeft) {
        // 根据不同时间范围设置不同的过期时间
        long expireHours = getExpireHours(timeLeft);
        redisUtils.set(reminderKey, "1", expireHours, TimeUnit.HOURS);
    }

    /**
     * 获取Redis记录的过期时间
     */
    private long getExpireHours(Duration timeLeft) {
        long hours = timeLeft.toHours();
        if (hours <= 24 && hours > 20) {
            return 5;  // 24-20小时的提醒记录保存5小时
        } else if (hours <= 12 && hours > 8) {
            return 5;  // 12-8小时的提醒记录保存5小时
        } else if (hours <= 4 && hours > 2) {
            return 3;  // 4-2小时的提醒记录保存3小时
        } else {
            return 2;  // 1小时内的提醒记录保存2小时
        }
    }
} 